• 问题

    在面对equals方法时,会有这样的疑问,什么时候该覆盖equals方法,什么时候不应该覆盖,也就是说覆盖equals方法的时机是什么?如果覆盖equals方法,那么应该写?

  • 解决

    1. 覆盖equals方法的时机

      覆盖equals方法看起来似乎很简单,但是有许多覆盖方式会导致错误,并且后果非常严重,最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每个实例都只与它自身相等。下面这几种情况就不需要覆盖equals()方法:

      • 类的每个实例本质上都是唯一的。对于代表活动实体而不是值(value)的类来说确实如此,例如Thread。Object提供的equals实现对于这些类来说是正确的行为;
      • 不关心类是否提供了“逻辑相等(logical equality)”的测试功能。如java.util.Random覆盖了equals,以检查两个Random实例是否产生相同的随机序列,但是调用者并不期望这样的功能。在这样的情况下,从Object继承得到的equals实现已经足够了;
      • 超类已经覆盖了equals,从超类继承过来的行为对于子类来说也是合适的。例如大多数Set实现都从AbstractSet继承equals实现,类似的有List和Map等;
      • 类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用。
    2. 覆盖equals方法的规范写法

      在覆盖equals方法时,需要遵守的约定有:

      • 自反性:对于任何非null的引用值x,x.equals(x)必须返回true;
      • 对称性:对于任何非null的引用值x,y,当且仅当y.equals(x)返回true时,x.equals(y)也应该返回true;
      • 传递性:对于任何非null得引用值x、y和z,如果x.equals(y)返回true时,并且y.equals(z)也返回true,那么x.equals(z)也返回true;
      • 一致性:对于任何非null得引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,那么多次调用x.equals(y)就会一致的返回true,或者一致的返回false;
      • 非空性:对于任何非null的引用值x,x.equals(null)必须返回false;

      编写的技巧有:

      • 使用==操作符检查“参数是否为这个对象的引用”;
      • 使用instanceof操作符检查“参数是否为正确的类型”;
      • 经过instanceof类型检查之后把参数转换成正确的类型;
      • 对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域相匹配。对于不是double和float的基本类型,可以使用==进行比较,对于引用类型,可以递归调用equals方法,对于float域,可以使用Float.compare方法,对于double域,可以使用Double.compare方法;
      • 当编写完equals方法时,应该问自己三个问题:它是否满足对称性、传递性、以及一致性;
      • 覆盖equals方法总要覆盖hashCode()方法;
      • 判断各个域值是否相等的逻辑不要过于复杂;
      • 不要将所覆盖的equals方法中的入参Object对象替换成其他对象,应该使用@Override。
  • 结论

    当面对equals方法时,应该根据覆盖equals方法的时机去判断是否需要覆盖equals方法,如果需要覆盖equals方法时,要严格遵守equals方法的规范。

results matching ""

    No results matching ""